﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.ServiceModel.DomainServices.Client;
using System.Linq;
using Scoreboard.Interfaces;
using Scoreboard.Model;
using System.Collections.ObjectModel;
using Microsoft.Practices.Composite.Presentation.Commands;
using Scoreboard.Data;
using Scoreboard.Basement;
using Scoreboard.Basement.ViewModels;
using Microsoft.Practices.Composite.Events;
using Scoreboard.Basement.Events;

namespace Scoreboard.Tournaments
{
	public class ViewModel : PageViewModel
	{
		private ITournamentRepository _tournamentRepository;
		private IUserRepository _userRepository;
		private IGameRepository _gameRepository;

		private int _currentTournamentId;

		private IEnumerable<Tournament> _tournaments;
		private Tournament _selectedTournament;
		private bool _isLoadingTournaments;
		private bool _operationInProgress;

		public ViewModel(ITournamentRepository tournamentRepository, IUserRepository userRepository, IGameRepository gameRepository)
		{
			_tournamentRepository = tournamentRepository;
			_userRepository = userRepository;
			_gameRepository = gameRepository;

			JoinCommand = new DelegateCommand<object>(JoinCommandHandler);
			LeaveCommand = new DelegateCommand<object>(LeaveCommandHandler);
			AddResultCommand = new DelegateCommand<object>(AddResultCommandHandler);			

			AddUpdater(EntityTypes.Tournaments, LoadTournaments);			
		}

		public ICommand JoinCommand { get; private set; }
		public ICommand LeaveCommand { get; private set; }
		public ICommand AddResultCommand { get; private set; }

		protected override string Name
		{
			get
			{
				return "Tournaments";
			}
		}

		public IEnumerable<Tournament> Tournaments
		{
			get
			{
				if (_tournaments == null)
				{
					LoadTournaments();
				}
				return _tournaments;
			}
			set
			{
				_tournaments = value;
				FirePropertyChanged("Tournaments");
			}
		}

		public Tournament SelectedTournament
		{
			get
			{
				return _selectedTournament;
			}
			set
			{
				_selectedTournament = value;
				FirePropertyChanged("SelectedTournament");
				FirePropertyChanged("IsTournamentSelected");
				RefreshCommands();
			}
		}

		public bool IsTournamentSelected
		{
			get
			{
				return SelectedTournament != null;
			}
		}


		public bool IsBusy
		{
			get
			{
				return _operationInProgress || _isLoadingTournaments;
			}
		}		

		private void LoadTournaments()
		{
			if (_isLoadingTournaments)
			{
				return;
			}
			_tournamentRepository.GetTournaments(LoadTournamentsCompleted);			
			_isLoadingTournaments = true;
		}

		private void LoadTournamentsCompleted(LoadOperation<Tournament> operation)
		{
			Tournaments = operation.Entities;
			_isLoadingTournaments = false;
			if (Tournaments != null && Tournaments.Count() > 0)
			{
				SelectedTournament = Tournaments.First();
			}
		}

		protected override void RefreshCommands()
		{
			Commands.Clear();

			if (!WebContext.Current.User.IsRegistered || SelectedTournament == null)
			{
				return;
			}

			if (SelectedTournament.IsFinished)
			{
				return;
			}
			if (SelectedTournament.Stages.Count == 0)
			{
				if (SelectedTournament.Participates(WebContext.Current.User))
				{
					Commands.Add(new UserCommand("Отказаться", LeaveCommand));
				}
				else
				{
					Commands.Add(new UserCommand("Участвовать", JoinCommand));
				}
			}
			else
			{
				if (SelectedTournament.UserCanAddResult(WebContext.Current.User))
				{
					Commands.Add(new UserCommand("Добавить результат", AddResultCommand));
				}
			}
		}		

		private void JoinCommandHandler(object parameter)
		{
			if (IsBusy)
			{
				return;
			}

			if (_tournamentRepository.CurrentUser == null)
			{
				return;
			}

			OperationStarted();

			var participant = new Participant { Player = _tournamentRepository.CurrentUser };			

			SelectedTournament.Participants.Add(participant);
			_tournamentRepository.SubmitChanges(JoinCompleted);
		}

		private void JoinCompleted(SubmitOperation operation)
		{
			RefreshCommands();
			OperationCompleted();
		}

		private void LeaveCommandHandler(object parameter)
		{
			if (IsBusy)
			{
				return;
			}

			OperationStarted();

			var me = SelectedTournament.Me;
			SelectedTournament.Participants.Remove(me);
			_tournamentRepository.SubmitChanges(LeaveCompleted);
		}

		private void LeaveCompleted(SubmitOperation operation)
		{
			RefreshCommands();
			OperationCompleted();
		}

		private void AddResultCommandHandler(object parameter)
		{
			if (IsBusy)
			{
				return;
			}

			var currentGroup = SelectedTournament.GetCurrentGroupForCurrentUser();
			if (currentGroup == null || currentGroup.Stage.IsFinished)
			{
				return;
			}

			var playersLeftToPlayWith = currentGroup.GetUsersLeftToPlayWith();

			var dialogService = ServiceLocator.Get<IDialogService>();

			var viewModel = 
				new Scoreboard.CommonViews.AddResultDialogViewModel(currentGroup.Id, 
																	playersLeftToPlayWith, 
																	_userRepository, 
																	_gameRepository, 
																	AddResultCallback);
			var addResultDialog = new Scoreboard.CommonViews.AddResultDialog(viewModel);
			_currentTournamentId = SelectedTournament.Id;
			dialogService.ShowDialog(addResultDialog);
		}

		private void OperationStarted()
		{
			_operationInProgress = true;
		}

		private void OperationCompleted()
		{
			_operationInProgress = false;
		}

		private void AddResultCallback(InvokeOperation operation)
		{
			if (!operation.HasError)
			{
				var eventAggregator = ServiceLocator.Get<IEventAggregator>();
				var dataChangedEvent = eventAggregator.GetEvent<DataChangedEvent>();
				_tournamentRepository.GetTournament(_currentTournamentId, RefreshCurrentTournamentCallback);
				dataChangedEvent.Publish(EntityTypes.Users);
			}
		}

		private void RefreshCurrentTournamentCallback(LoadOperation<Tournament> operation)
		{
			RefreshCommands();
			var tournament = Tournaments.Where(t => t.Id == _currentTournamentId).Single();
			tournament.RefreshAllGroups();
		}
	}
}
